package org.xqp.hrm.service.impl;
import lombok.extern.log4j.Log4j;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import org.xqp.hrm.constants.RedisConstants;
import org.xqp.hrm.dto.SMSCodeSendDto;
import org.xqp.hrm.exception.GlobalException;
import org.xqp.hrm.service.IVerifyCodeService;
import org.xqp.hrm.to.SendVerifyCodeTo;
import org.xqp.hrm.util.AssertUtil;
import org.xqp.hrm.util.StrUtils;
import org.xqp.hrm.util.VerifyCodeUtils;

import java.io.IOException;
import java.util.Date;
import java.util.concurrent.TimeUnit;

@Service
@Slf4j
public class VerifyCodeServiceImpl extends IVerifyCodeService {

    @Autowired
    private RedisTemplate<Object,Object> redisTemplate;

    /**
     *                                                         图片验证码验证
     *  1.先判断数据是否为空
     *  2.生成4位数验证码
     *  3.将key和四位数验证码存入redis
     *  4.用工具类生成验证码图片
     *  5.将验证码图片转换为base64字符串
     * @param key
     * @return
     */
    @Override
    public String createImageCode(String key) {
        // 1.先判断数据是否为空
        AssertUtil.isNotEmpty(key, "非法请求，，你有问题哦！");
        // 2.生成4位数验证码
        String imageCode = StrUtils.getComplexRandomString(4);
        // 3.将key和四位数验证码存入redis
        redisTemplate.opsForValue().set(key, imageCode,10L, TimeUnit.MINUTES);
        // 4.用工具类生成验证码图片
        // 5.将验证码图片转换为base64字符串
        try {
            return VerifyCodeUtils.verifyCode(130, 35, imageCode);
        } catch (IOException e) {
            e.printStackTrace();
            throw  new GlobalException("图片验证码创建失败");
        }
    }

    /**
     *                             手机短信验证码验证
     * 1.判断参数（非空判断正则表达式判断手机号是否符合图片验证码是否为空是否正确）
     * 2.获取前端传过来的key然后通过这个key去redis中去取value也就是验证码，再将这个验证码和前端传过来的验证码进行比较
     * 3.通过key去redis中去取上一次的手机短信验证码，然后这里是个if  else
     *  3.1 if如果从redis中取到了value也就是上一次短信验证码，那么再进行判断用当前时间减去上一次发送短信验证码的时间是否大于60秒，小于60秒提示他请勿频繁发送
     *     如果大于60秒那么就将上次的手机短信嘛获取作为这次要 发送的短信验证码再次发送
     *  3.2  else  没有从redis中获取到手机验证码那么就 有可能是手机验证码在redis中已过期，或者是第一次获取手机验证码
     *       这两种情况不管是哪种都要重新生成手机短信验证码
     * 4.将获取到的手机验证码通过短信发送接口，发送
     * 5.将发送信息存入redis
     * 6.将发送信息存一份到数据库
     * 7.从redis中删除图片中验证码
     */
    @Override
    public void sendSmsCode(SMSCodeSendDto dto) {
        //  1.判断参数（非空判断正则表达式判断手机号是否符合图片验证码是否为空是否正确）
        String imageCode = dto.getImageCode();// 获取前端传过来的图片验证码
        String imageCodeKey = dto.getImageCodeKey(); // 获取前端传给我们的redis中的key  value中装的是生成的图片验证码
        String mobile = dto.getMobile();// 前端传过来的电话号码
        AssertUtil.isNotEmpty(imageCode,"图片验证码不可为空" );
        AssertUtil.isNotEmpty(imageCodeKey,"非法的请求" );
        AssertUtil.isNotEmpty(mobile,"手机号不可为空" );
        //  2.获取前端传过来的key然后通过这个key去redis中去取value也就是验证码，再将这个验证码和前端传过来的验证码进行比较
        String imageCodeFromRedis = (String) redisTemplate.opsForValue().get(imageCodeKey);
        AssertUtil.isEqualsIgnoreCase(imageCode,imageCodeFromRedis ,"图片验证码输入错误" );
        //  3.通过key去redis中去取上一次的手机短信验证码，然后这里是个if  else
        String code = null; // 先声明一个code
        String key = String.format(RedisConstants.KEY_SMS_CODE,mobile); // 声明一个key常量，并将mobile替换常量中的%s
        SendVerifyCodeTo lastSend = (SendVerifyCodeTo) redisTemplate.opsForValue().get(key); // 通过key从redis中获取value
        Long nowTime = new Date().getTime(); // 获取创建短信验证码时的时间戳
        //   3.1 if如果从redis中取到了value也就是上一次短信验证码，那么再进行判断用当前时间减去上一次发送短信验证码的时间是否大于60秒，小于60秒提示他请勿频繁发送
        if(lastSend != null){
            //* 3.2.判断当前时间 - 上一次发送时间 大于60S正常运行，小于60秒报错
            boolean canSend = (nowTime - lastSend.getSendTime()) / 1000 < 60; //
            AssertUtil.isTrue(!canSend, "发送频繁，请稍后重试");
            //* 3.3.获取到上一次的验证码作为此次发送的验证码
            code = lastSend.getCode();
        }else{
            //* 4.如果没有上一次，生成一个短信验证码(随机数)
            code = StrUtils.getRandomString(6);
        }
        //  5.将获取到的手机验证码通过短信发送接口，发送
        log.info("您的短信验证码为：{}，请在{}分钟内使用",code ,10);
        //  6.将发送信息存入redis
        redisTemplate.opsForValue().set(key,new SendVerifyCodeTo(code,nowTime));
        //  7.将发送信息存一份到数据库
        //  8.从redis中删除图片中验证码
        redisTemplate.delete(imageCodeKey);
    }
}
